﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Windows;
using System.Reflection;
using System.Configuration;
using System.Xml.Serialization;
using nGSO;
using nGSO.Config;
using System.Globalization;

namespace nGSO
{
    /// <summary>
    /// Algorithm configuration, initial agents settings
    /// </summary>
    [XmlRoot("config")]
    public class GsoConfig
    {
        public int Population { get; set; }
        public int DefaultLuminescence { get; set; }
        public int MaxIterations { get; set; }
        public int SpaceSize { get; set; }
        public int DesiredNoOfNeighbors { get; set; }
        public double BetaConst { get; set; }
        public double StepSize { get; set; }
        // Constant radial sensor range
        public double RadialSensorRange { get; set; }
        public int Dims { get; set; }
        [XmlIgnore]
        public List<BaseAfterAgentMoveExtension> AfterAgentMoveExtensions {get; set;}
        public string FitnessFunctionCode { get; set; }
        public static IMultimodalFun FitnessFunPointer { get; set; }
        public bool UseRandomizeSelector { get; set; }
        public int StepInterval { get; set; }
        public double Decay { get; set; }
        public double LuciferinEnhancement { get; set; }
        internal INeighbourSelector NeighbourSelector { get;  set; }

        public OptimizationTaskElement SelectedOptimizationTask { get; set; }

        public GsoConfig()
        {
            Debug.WriteLine("Setup algorithm ... ");

            NumberFormatInfo nfi = new NumberFormatInfo() { NumberDecimalSeparator = "," };

                #region Set properties
                // possible use of Convert.ChangeType + reflection
                Decay = double.Parse(ConfigurationManager.AppSettings["Decay"], nfi);
                LuciferinEnhancement = double.Parse(ConfigurationManager.AppSettings["LuciferinEnhancement"], nfi);
                BetaConst = double.Parse(ConfigurationManager.AppSettings["BetaConst"], nfi);
                DesiredNoOfNeighbors = int.Parse(ConfigurationManager.AppSettings["DesiredNoOfNeighbors"]);
                StepSize = double.Parse(ConfigurationManager.AppSettings["StepSize"], nfi);
                DefaultLuminescence = int.Parse(ConfigurationManager.AppSettings["DefaultLuminescence"], nfi);
                Dims = byte.Parse(ConfigurationManager.AppSettings["Dims"], nfi);
                UseRandomizeSelector = bool.Parse(ConfigurationManager.AppSettings["UseRandomizeSelector"]);
                #endregion

                SelectedOptimizationTask = OptimizationTaskConfig.Tasks.First().Value;
            
            if (UseRandomizeSelector) // todo umozliwienie konfiguracji z UI
                NeighbourSelector = new RandomizeSelector();
            else
                NeighbourSelector = new MaximumProbabilitySelector();

            

            SetOptimizationTaskParameters();
            

            CompileFitnessEvaluator();

            LoadAfterMoveExt();

            PrintInitialAlgorithmConfig();

            
        }

        public GsoConfig(double betaConst, int defaultLuminescence, double decay, int population, double radialSensorRange, int maxIterations,
            int desiredNoOfNeighbours, double luceferinEnhancment, double stepSize, int spaceSize, INeighbourSelector selector)
        {
            BetaConst = betaConst;
            DefaultLuminescence = defaultLuminescence;
            Decay = decay;
            Population = population;
            RadialSensorRange = radialSensorRange;
            MaxIterations = maxIterations;
            DesiredNoOfNeighbors = desiredNoOfNeighbours;
            LuciferinEnhancement = luceferinEnhancment;
            StepSize = stepSize;
            SpaceSize = spaceSize;

            AfterAgentMoveExtensions = new List<BaseAfterAgentMoveExtension>();
            NeighbourSelector = selector;
        }

        public void SetOptimizationTaskParameters()
        {
            Population = SelectedOptimizationTask.Population;
            MaxIterations = SelectedOptimizationTask.MaxIterations; 
            SpaceSize = SelectedOptimizationTask.SpaceSize; 
            FitnessFunctionCode = SelectedOptimizationTask.FunctionBody;
            RadialSensorRange = SelectedOptimizationTask.RadialSensorRange;
        }
        
        public void CompileFitnessEvaluator()
        {
            string classDef = DynamicFunctionGenerator.GenerateCode("nGSO", "MultimodalFunDefHelper", SelectedOptimizationTask.FunctionBody);

            Assembly assemblyFromMem = DynamicFunctionGenerator.CompileInMemory(classDef);
            if (assemblyFromMem == null)
            {
                throw new ArgumentNullException("Unable to create dynamic assembly!");

            }
            Type dynType = assemblyFromMem.GetType("nGSO.MultimodalFunDefHelper", true);
            FitnessFunPointer = Activator.CreateInstance(dynType) as IMultimodalFun;
        }
        
        private void PrintInitialAlgorithmConfig()
        {
            PropertyInfo[] setupValues = GetType().GetProperties();
            foreach (var item in setupValues)
            {
                Debug.WriteLine("Property " + item.Name + " = " + item.GetValue(this, null));
            }
        }

        private void LoadAfterMoveExt()
        {
            string configKey = "AfterMoveExt";

            AfterAgentMoveExtensions = new List<BaseAfterAgentMoveExtension>();

            foreach (string key in ConfigurationManager.AppSettings.Keys)
            {
                if (key.StartsWith(configKey))
                {
                    var extension = Activator.CreateInstance(null, ConfigurationManager.AppSettings[key]).Unwrap() as BaseAfterAgentMoveExtension;
                    extension.Enabled = false;
                    AfterAgentMoveExtensions.Add(extension);
                }
            }
        }

    }
}
